package net.hzlj.platform.enterprise.socket.netty;

import android.util.Log;

import net.hzlj.platform.enterprise.config.HttpConfig;
import net.hzlj.platform.enterprise.socket.SocketService;

import java.nio.charset.Charset;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * @Description:
 * @Author: Jason Zhang
 * @Date: 2017/06/28
 */

public class NettyClientManager implements SocketService{

    public static final String TAG = NettyClientManager.class.getSimpleName();

    private static final NettyClientManager instance = new NettyClientManager();

    private Bootstrap bootstrap;

    private SocketChannel socketChannel;

    private ChannelFuture channelFuture;

    private EventLoopGroup eventLoopGroup;

    public static NettyClientManager getInstance() {
        return instance;
    }

    private NettyClientManager() {
        initBootstrap();
    }

    private void initBootstrap(){
        eventLoopGroup = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        bootstrap.group(eventLoopGroup);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
        bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,2000);
        bootstrap.remoteAddress(HttpConfig.SOCKET_IP,HttpConfig.SOCKET_PORT);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            public void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline().addLast(new LineBasedFrameDecoder(10240));
                //ByteBuf delimiter = Unpooled.copiedBuffer("$_$".getBytes());
                //ch.pipeline().addLast(new DelimiterBasedFrameDecoder(10240,delimiter));
                ch.pipeline().addLast(new StringDecoder(Charset.forName("utf-8")));
                ch.pipeline().addLast(new StringEncoder(Charset.forName("utf-8")));
                ch.pipeline().addLast(new NettyClientHandler());
            }
        });
    }


    @Override
    public void reconnect() {
        if (!isConnection()){
            try {
                bootstrap.remoteAddress(HttpConfig.SOCKET_IP,HttpConfig.SOCKET_PORT);
                //channelFuture = bootstrap.connect(HttpConfig.SOCKET_IP,HttpConfig.SOCKET_PORT).awaitUninterruptibly();
                channelFuture = bootstrap.connect(HttpConfig.SOCKET_IP,HttpConfig.SOCKET_PORT).awaitUninterruptibly();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //eventLoopGroup.shutdownGracefully();
            }
        }
    }

    @Override
    public void sendMessage(final String message) {
        if (!isConnection()){
            reconnect();
        }
        if (isConnection()){
            byte [] req = (message + System.getProperty("line.separator")).getBytes();
            ByteBuf buf = Unpooled.buffer(req.length);
            buf.writeBytes(req);
            channelFuture.channel().writeAndFlush(buf).addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    Log.i(TAG,"发送" + (future.isSuccess() ? "成功：" : "失败：") + message);
                }
            });
        }
    }

    @Override
    public void close() {
        if (isConnection()){
            channelFuture.channel().close().syncUninterruptibly();
        }
        if (eventLoopGroup != null) {
            eventLoopGroup.shutdownGracefully();
        }
    }

    @Override
    public boolean isConnection() {
        return eventLoopGroup != null && !eventLoopGroup.isShutdown() && channelFuture != null && channelFuture.isSuccess() && channelFuture.channel().isOpen() && channelFuture.channel().isActive();
    }
}
